package edu.towson.cosc.cosc455.pjemmott;

import java.util.*;

import edu.towson.cosc.cosc455.interfaces.SyntaxAnalyzer;

public class PaulSyntaxAnalyzer implements SyntaxAnalyzer {

	private MyLexicalAnalyzer lexer = new MyLexicalAnalyzer();
	private SemanticAnalyzer semantics = new SemanticAnalyzer();

	// variables holds names of a variable after #NAME tag, values holds the
	// value after the #VALUE tag
	static String[] variable = new String[10];
	static int counter = 0;
	static String[] values = new String[10];

	// gets the next token which will be a tag after the text
	public void text() throws CompilerException {

		lexer.getNextToken(mycompiler.token);

	}

	// text inside of other tags
	public void innerText() throws CompilerException {

		if (lexer.token2.equalsIgnoreCase("#START USE"))
			use();
		else if (lexer.token2.equalsIgnoreCase("#NEWLINE"))
			newline();
		else if (lexer.token2.charAt(0) != '#')
			text();
		else {

		}

	}

	// beginning state called inside of mycompiler
	public void document(String token) throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START DOCUMENT")) {
			String message = "A #START DOCUMENT annotation was expected when a "
					+ token + " was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);

		if (lexer.token2.equalsIgnoreCase("#START DEFINE")) {
			define();

		}
		if (lexer.token2.equalsIgnoreCase("#START HEAD")) {
			head();
			lexer.getNextToken(mycompiler.token);

		}

		// making body recursive
		body();
		body();
		body();
		if (!lexer.token2.equalsIgnoreCase("#END DOCUMENT")) {
			String message = "A #END DOCUMENT annotation was expected when a "
					+ lexer.token2 + " was found!";

			throw new CompilerException(message);
		}
		// check to see if any text after token
		if (lexer.scans.hasNext()) {
			String message = "text found after #END DOCUMENT tag was found!";

			throw new CompilerException(message);
		} else {

		}
		// then call the semantic analyzer
		semantics.convert(lexer.s, variable, values);
	}

	// body of file
	public void body() throws CompilerException {
		if (lexer.token2.equalsIgnoreCase("#START PARAGRAPH"))
			paragraph();
		if (lexer.token2.equalsIgnoreCase("#START BOLD"))
			bold();
		if (lexer.token2.equalsIgnoreCase("#START ITALICS"))
			italics();
		if (lexer.token2.equalsIgnoreCase("#START LIST"))
			list();
		// if either tag is found go to inner text which calls the corresponding
		// function
		else if (lexer.token2.equalsIgnoreCase("#START USE")
				|| lexer.token2.equalsIgnoreCase("#NEWLINE")
				|| lexer.token2.charAt(0) != '#') {
			lexer.getNextToken(mycompiler.token);
			innerText();
		} else {

		}

	}

	// syntax for newline
	public void newline() throws CompilerException {
		// TODO Auto-generated method stub

		if (!lexer.token2.equalsIgnoreCase("#NEWLINE")) {
			String message = "A #NEWLINE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		String nexttoken = lexer.getNextToken(mycompiler.token);

	}

	// head function which calls title
	@Override
	public void head() throws CompilerException {
		if (!lexer.token2.equalsIgnoreCase("#START HEAD")) {
			String message = "A #START HEAD annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		lexer.getNextToken(mycompiler.token);
		title();
		lexer.getNextToken(mycompiler.token);

		if (!lexer.token2.equalsIgnoreCase("#END HEAD")) {
			String message = "A #END HEAD annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// title function which calls text
	@Override
	public void title() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START TITLE")) {
			String message = "A #START TITLE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		text();
		lexer.getNextToken(mycompiler.token);

		if (!lexer.token2.equalsIgnoreCase("#END TITLE")) {
			String message = "A #END TITLE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// paragraph function which has a recursive call to inner paragraph in it
	@Override
	public void paragraph() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START PARAGRAPH")) {
			String message = "A #START PARAGRAPH annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);

		if (lexer.token2.equalsIgnoreCase("#START PARAGRAPH"))
			paragraph();
		if (lexer.token2.equalsIgnoreCase("#START DEFINE"))
			define();
		// enter inner paragraph until paragraph ends
		if (!lexer.token2.equalsIgnoreCase("#START PARAGRAPH")
				|| lexer.token2.equalsIgnoreCase("#START DEFINE")) {
			while (!lexer.token2.equalsIgnoreCase("#END PARAGRAPH")) {
				innerParagraph();
			}
		}

		if (!lexer.token2.equalsIgnoreCase("#END PARAGRAPH")) {
			String message = "A #END PARAGRAPH annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		lexer.getNextToken(mycompiler.token);

	}

	// all the functions accessible from inner paragraph
	public void innerParagraph() throws CompilerException {

		lexer.getNextToken(mycompiler.token);

		if (lexer.token2.equalsIgnoreCase("#START BOLD"))
			bold();
		else if (lexer.token2.equalsIgnoreCase("#START ITALICS"))
			italics();
		else if (lexer.token2.equalsIgnoreCase("#START LIST"))
			list();
		else if (lexer.token2.equalsIgnoreCase("#NEWLINE"))
			newline();
		else if (lexer.token2.equalsIgnoreCase("#AUDIO"))
			audio();
		else if (lexer.token2.equalsIgnoreCase("#VIDEO"))
			audio();
		else {

		}

	}

	// bold syntax function
	@Override
	public void bold() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START BOLD")) {
			String message = "A #START BOLD annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		String nexttoken = lexer.getNextToken(mycompiler.token);
		if (lexer.token2.equalsIgnoreCase("#START DEFINE"))
			define();
		else
			text();

		if (!lexer.token2.equalsIgnoreCase("#END BOLD")) {
			String message = "A #END BOLD annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// italics syntax function
	@Override
	public void italics() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START ITALICS")) {
			String message = "A #START ITALICS annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);
		if (lexer.token2.equalsIgnoreCase("#START DEFINE"))
			define();
		else
			text();

		if (!lexer.token2.equalsIgnoreCase("#END ITALICS")) {
			String message = "A #END ITALICS annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// audio syntax function
	@Override
	public void audio() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START AUDIO")) {
			String message = "A #START AUDIO annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);
		text();

		if (!lexer.token2.equalsIgnoreCase("#END AUDIO")) {
			String message = "A #END AUDIO annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// video syntax function
	@Override
	public void video() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START VIDEO")) {
			String message = "A #START VIDEO annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);
		text();

		if (!lexer.token2.equalsIgnoreCase("#END VIDEO")) {
			String message = "A #END VIDEO annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
	}

	// list syntax function
	@Override
	public void list() throws CompilerException {
		// TODO Auto-generated method stub
		if (!lexer.token2.equalsIgnoreCase("#START LIST")) {
			String message = "A #START LIST annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		lexer.getNextToken(mycompiler.token);

		item();

		if (!lexer.token2.equalsIgnoreCase("#END LIST")) {
			String message = "A #END LIST annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

	}

	// all of the accessible tags within inner list
	public void innerList() throws CompilerException {

		if (lexer.token2.equalsIgnoreCase("#START BOLD"))
			bold();
		else if (lexer.token2.equalsIgnoreCase("#START ITALICS"))
			italics();
		else if (lexer.token2.equalsIgnoreCase("#START LIST"))
			list();
		else {
			innerText();
		}
	}

	// item syntax function
	@Override
	public void item() throws CompilerException {

		if (!lexer.token2.equalsIgnoreCase("#START ITEM")) {
			String message = "A #START ITEM annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);
		if (lexer.token2.equalsIgnoreCase("#START DEFINE")) {
			define();
		}
		// recursive call to innerlist
		innerList();
		innerList();

		if (!lexer.token2.equalsIgnoreCase("#END ITEM")) {
			String message = "A #END ITEM annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		// if the next token is item, recursively call self
		lexer.getNextToken(mycompiler.token);
		if (lexer.token2.equalsIgnoreCase("#START ITEM"))
			item();
		else {

		}
	}

	// define syntax function
	@Override
	public void define() throws CompilerException {

		if (!lexer.token2.equalsIgnoreCase("#START DEFINE")) {
			String message = "A #START DEFINE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}

		lexer.getNextToken(mycompiler.token);
		// checks to see if name comes next like proper syntax
		if (!lexer.token2.equalsIgnoreCase("#NAME")) {
			String message = "A #NAME annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		// gets the next token which is the name of a variable
		String var;
		var = lexer.getNextToken(mycompiler.token);

		/*
		 * checks to see if the variable name is already in an array of the
		 * names if it is in it, move to the next spot and rename the var (for
		 * changing var with same name ie step 7)
		 */
		if (var.equalsIgnoreCase(variable[counter])
				|| variable[counter] != null) {
			counter++;
			variable[counter] = var + counter;

		} else {
			variable[counter] = var;
		}
		text();
		// checks that #VALUE follows as in proper syntax
		if (!lexer.token2.equalsIgnoreCase("#VALUE")) {
			String message = "A #VALUE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		// puts that value in a second array that corresponds to the proper name
		values[counter] = lexer.getNextToken(mycompiler.token);
		text();

		if (!lexer.token2.equalsIgnoreCase("#END DEFINE")) {
			String message = "A #END DEFINE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		// if the next token is define, recursively call self
		lexer.getNextToken(mycompiler.token);
		if (lexer.token2.equalsIgnoreCase("#START DEFINE")) {
			define();
		}
	}

	// use syntax function
	@Override
	public void use() throws CompilerException {

		if (!lexer.token2.equalsIgnoreCase("#START USE")) {
			String message = "A #START USE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		// get the next token
		String words;
		words = lexer.getNextToken(mycompiler.token);

		//check to see if the new token is matches up with pre-existing macro tag
		for (int i = 0; i <= counter; i++) {

			if (words.equalsIgnoreCase(variable[i])) {
				break;
			}
		}
		//if its not print out the error message
		if (!variable[counter].equalsIgnoreCase(words)) {
			String message = "invalid macro tag " + words;

			throw new CompilerException(message);
		}

		text();

		if (!lexer.token2.equalsIgnoreCase("#END USE")) {
			String message = "A #END USE annotation was expected when a"
					+ lexer.token2 + "was found!";

			throw new CompilerException(message);
		}
		lexer.getNextToken(mycompiler.token);

	}

}
